package com.xhga.transaction.common.annotation;

import com.xhga.transaction.common.entity.TransactionLog;
import com.xhga.transaction.common.service.TransactionLogService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 动态代理实现
 * Created by HuaWeiBo on 2019/4/23.
 */

public class XHGAProxy<T> implements InvocationHandler {

    private static final Logger logger = LoggerFactory.getLogger(XHGAProxy.class);

    private PlatformTransactionManager manager;
    private TransactionLogService logService;
    private T service;

    public XHGAProxy(PlatformTransactionManager manager,
                     TransactionLogService logService, T service) {
        this.manager = manager;
        this.logService = logService;
        this.service = service;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 方法是否添加@XHGATransaction注解
        boolean flag = false;
        XHGATransaction annotation = method.getAnnotation(XHGATransaction.class);
        if (annotation != null) {
            flag = true;
        } else {
            Class<?>[] parameterTypes = method.getParameterTypes();
            Method methodService = service.getClass().getMethod(method.getName(), parameterTypes);
            annotation = methodService.getAnnotation(XHGATransaction.class);
            if (annotation != null) {
                flag = true;
            }
        }
        Object invoke;
        if (! flag) {
            return method.invoke(service, args);
        }
        // 分布式事务实现
        String type = annotation.type();
        String[] names = annotation.names();
        String name = annotation.name();
        int count = annotation.serverCount();
        // 获取事务No
        String centreNo = logService.getCentreNo(type, names, count, name);
        logger.info("XHGA事务开启--type:{},name:{},no:{}.", type, name, centreNo);
        TransactionLog transactionLog = new TransactionLog();
        transactionLog.setCount(count);
        transactionLog.setFailedCount(0);
        transactionLog.setPrepareCount(count);
        transactionLog.setCentreNo(centreNo);
        try {
            logService.addTransactionLog(transactionLog);
        } catch (Exception e) {
            logger.info("XHGA事务日志服务异常:no:{}" + centreNo);
            throw new Exception("log server: not open.");
        }
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        TransactionStatus transactionStatus = manager.getTransaction(def);
        try {
            invoke = method.invoke(service, args);
            logService.updatePrepareCount(centreNo, name);
            logService.returnFailedCountExceptionNoDelay(centreNo);
        } catch (Exception e) {
            manager.rollback(transactionStatus);
            logService.updateFailedCount(centreNo, name);
            // 异常删除centreNo
            logService.updateCentreNo(type, centreNo, count);
            logger.info("XHGA事务异常回滚--no:{}", centreNo);
            return 0;
        }
        manager.commit(transactionStatus);
        logger.info("XHGA事务正常结束--no:{}", centreNo);
        return invoke;
    }

}
